#ifndef VObject_First
#define VObject_First
#ifdef __GNUG__
#pragma interface
#endif

#include "Port.h"
#include "EvtHandler.h"
#include "Command.h"
#include "CmdNo.h"
#include "Container.h"

class Clipper;
class View;
class Window;
class Collection;
class Picture;
class Manager;

enum VObjFlags {
	eVObjEnabled    =   BIT(eEvtLast+1),
	eVObjOpen       =   BIT(eEvtLast+2),
	eVObjHFixed     =   BIT(eEvtLast+3),
	eVObjVFixed     =   BIT(eEvtLast+4),
	eVObjLayoutCntl =   BIT(eEvtLast+5),
	eVObjKbdFocus   =   BIT(eEvtLast+6),
	eVObjShowPage   =   BIT(eEvtLast+7),
	eVObjHighlight  =   BIT(eEvtLast+8),
	eVObjDefault    =   eVObjEnabled,
	eVObjLast       =   eEvtLast + 8
};

enum VObjAlign {
	eVObjHLeft      = BIT(0),
	eVObjHCenter    = BIT(1),
	eVObjHRight     = BIT(2),
	eVObjHExpand    = BIT(3),
	eVObjHEqual     = BIT(4),
	eVObjHGapExpand = BIT(5),
	eVObjH          = eVObjHLeft|eVObjHCenter|eVObjHRight,
	eVObjVTop       = BIT(8),
	eVObjVBase      = BIT(9),
	eVObjVCenter    = BIT(10),
	eVObjVBottom    = BIT(11),
	eVObjVExpand    = BIT(12),
	eVObjVEqual     = BIT(13),
	eVObjVGapExpand = BIT(14),
	eVObjV          = eVObjVTop|eVObjVBase|eVObjVCenter|eVObjVBottom
};

extern const int cAutoSize;
extern const Point gBorder;

typedef void (FeedbackFunc)(Clipper*, Command*, const Point&, const Point&, bool);

//---- VObject -----------------------------------------------------------------

class VObject : public EvtHandler {
	VObject *container;

public:
	Rectangle contentRect;

public:
	MetaDef(VObject);

	VObject(const Rectangle &r, int id= cIdNone);
	VObject(const Point &e, int id= cIdNone);
	VObject(int id= cIdNone);
	~VObject();

	void FreeAll();

	Point GetPortPoint(Point p);
	virtual Rectangle GetViewedRect();

	virtual int Size();
	virtual Iterator *MakeIterator(bool forward= TRUE, void *placement= 0);
	virtual VObject *SetAt(int at, VObject *vop);
	virtual VObject *At(int n);
	virtual void Add(VObject*);
	virtual VObject *Remove(VObject*);
	virtual void RemoveFromContainer();
	void SendDown(int, int, void*);

	//---- acessing ----------------------------
	bool Enabled()
		{ return TestFlag(eVObjEnabled); }
	virtual void Enable(bool b= TRUE, bool redraw= TRUE);
	void Disable(bool redraw= TRUE)
		{ Enable(FALSE, redraw); }
	virtual bool IsOpen();

	//---- sizes -------------------------------
	virtual Metric GetMinSize();
	int Width()
		{ return contentRect.extent.x; }
	int Height()
		{ return contentRect.extent.y; }
	int Base();
	Point GetExtent()
		{ return contentRect.extent; }
	Point GetOrigin()
		{ return contentRect.origin; };
	Rectangle ContentRect()
		{ return contentRect; }

	void SetContentRect(const Rectangle&, bool);
	virtual void SetExtent(Point);
	virtual void ExtentChanged(VObject *what);
	virtual void SetOrigin(Point);
	void SetWidth(int w)
		{ SetExtent(Point(w,Height())); }
	void SetHeight(int h)
		{ SetExtent(Point(Width(),h)); }
	void Move(const Point &delta, bool redraw= TRUE);

	void CalcExtent();
	virtual void Open(bool mode= TRUE);
	void Close()
		{ Open(FALSE); }

	void Align(const Point &at, const Metric &m, VObjAlign a);
	virtual bool ContainsPoint(Point p);

	//---- drawing ----------------------------
	virtual void Focus();
	virtual void DrawAll(Rectangle, bool highlight= FALSE);
	virtual void DrawInner(Rectangle, bool highlight= FALSE);
	virtual void DrawHighlight(Rectangle);
	virtual void Draw(Rectangle);
	virtual void Outline2(Point, Point);
	void Outline(const Point &delta);
		// alternative interface to Outline2
	void OutlineRect(const Rectangle &r);
		// alternative interface to Outline2
	virtual void Highlight(HighlightState);
	virtual void InvalidateRect(Rectangle r);
	virtual void InvalidateViewRect(Rectangle r);
	void ForceRedraw();
	void UpdateEvent();
	virtual GrCursor GetCursor(Point p);
	void Print();
	virtual void Scroll(int mode, Point scroll, bool redraw= TRUE);
	virtual void RevealRect(Rectangle, Point);
	virtual void RevealAlign(Rectangle r, VObjAlign al= VObjAlign(eVObjHLeft+eVObjVTop));
	void Reveal()
		{ RevealRect(contentRect, contentRect.extent); }
	Picture *AsPicture();

	Command *Input(Point lp, Token &t, Clipper *cl);
	virtual Command *DispatchEvents(Point lp, Token &t, Clipper *cl);
	virtual void DoTrackMouse(TrackPhase, Point);

	virtual VObject *Detect(BoolFun f, void *arg);
		// find first entry where f returns true
	VObject *FindItem(int);
	VObject *FindItem(Point);
	VObject *FindItem(VObject*);
	VObject *FindItemPtr(VObject *g);

	//---- container handling ------------------
	virtual void SetContainer(VObject*);
	virtual void ClearContainer(VObject*);
	VObject *GetContainer()
		{ return container; }
		
	VObject *FindContainerOfClass(Class *cla);
	View *GetView();
	Clipper *Getclipper();
	Window *GetWindow();
	Manager *GetManager();
	virtual Point ContainerPoint(Point);
	virtual void ReadEvent(Token &t);

	//---- keyboard focus
	bool WantsKbdFocus()
		{ return TestFlag(eVObjKbdFocus); }
		
	virtual Command *GetMover();
	virtual Command *GetStretcher();

	EvtHandler *GetNextHandler();
	virtual Command *DoButtonDownCommand(const Point&, const Token &t,
							int clicks, Clipper*);
	virtual Command *DoRightButtonDownCommand(Point, Token, int, Clipper*);
	virtual Command *DoLeftButtonDownCommand(Point, Token, int);
	virtual Command *DoMiddleButtonDownCommand(Point, Token, int);

	virtual Command *DoKeyCommand(int, Token);
	virtual Command *DoCursorKeyCommand(EvtCursorDir, Token);
	virtual Command *DoFunctionKeyCommand(int, Token);

	virtual Command *DoOtherEventCommand(Point, Token);
	virtual Command *TrackInContent(Point, Token, Command*);

	//---- generic methods --------------------
	OStream &PrintOn(OStream&);
	IStream &ReadFrom(IStream&);
	void CollectParts(Collection*);
};

//---- VObjectIter -------------------------------------------------------------

class VObjectIter {
	Iterator *seq;
	char space[64];
public:
	VObjectIter(VObject *vop, bool dir= cIterForward);
	VObjectIter(Iterator *it);
	~VObjectIter();
	VObject *operator()();
	void Reset(VObject *vop, bool dir= cIterForward);
	void Reset();
};

inline VObjectIter::VObjectIter(VObject *v, bool dir)
	{ seq= v->MakeIterator(dir, space); }

inline VObjectIter::VObjectIter(Iterator *it)
	{ seq= it; }

inline VObject *VObjectIter::operator()()
	{ return (VObject*) seq->operator()(); }

inline void VObjectIter::Reset()
	{ seq->Reset(); }
       
//---- VObjectCommand ----------------------------------------------------------

class VObjectCommand: public Command {
protected:
	VObjectCommand(VObject *g);
	void Init(VObject*, const Rectangle&, const Point&, GrCursor, int);
	Command *TrackMouse(TrackPhase, Point, Point, Point);
	void TrackConstrain(Point, Point, Point*);
	void TrackFeedback(Point, Point, bool);
	void DoIt();
	void UndoIt();

protected:
	VObject *vop;
	Rectangle oldRect, lastRect, constrainRect, newRect;
	Point delta, grid;
	GrCursor newcursor, oldcursor;
	bool firstmove;
	int hysterese;
};

//---- VObjectMover ------------------------------------------------------------

class VObjectMover: public VObjectCommand {
public:
	VObjectMover(VObject*);
	VObjectMover(VObject*, const Rectangle&);
	VObjectMover(VObject*, const Rectangle&, const Point&,
					GrCursor cr= eCrsMoveHand, int hy= 2);

	Command *TrackMouse(TrackPhase, Point, Point, Point);

protected:
	void Init(VObject*, const Rectangle&, const Point&, GrCursor, int);

protected:
	Point origin;
};

//---- VObjectStretcher --------------------------------------------------------

class VObjectStretcher: public VObjectCommand {
public:
	VObjectStretcher(VObject*);
	VObjectStretcher(VObject*, const Rectangle&);
	VObjectStretcher(VObject*, const Rectangle&, const Point &ms);
	VObjectStretcher(VObject*, const Rectangle&, const Point &ms,
			const Point&, GrCursor cr= eCrsMoveStretch, int hy= 2);

	Command *TrackMouse(TrackPhase, Point, Point, Point);
	void TrackConstrain(Point, Point, Point*);

protected:
	void Init(VObject*, const Rectangle&, const Point&, GrCursor,
												int, const Point&);
protected:
	Point minSize, p1, p2;
	int corner;
};

#endif
